﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Data.OleDb;
//using Sybase.Data.AseClient;
using System.IO;


namespace StudyAdoNet
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            _conn.StateChange += new StateChangeEventHandler(conn_StateChange);
            _connOdbc.StateChange += new StateChangeEventHandler(conn_StateChange);


        }

        OleDbConnection _conn = new OleDbConnection();
        OdbcConnection _connOdbc = new OdbcConnection();


        private const string _connString =
            "Provider=ASEOLEDB;Data Source=172.16.8.204:4100;Catalog=emdb_svil;User Id=gestore;Password=blevio;";
        // DBParm = "PROVIDER='SQLOLEDB',DATASOURCE='svil118',Database='emdb_curr'"
        private const string _connStringOdbc =
            "DSN=EMMAODBC;Uid=gestore;Pwd=blevio;";



        // Questo e' il mio delegato per la gestione dei cambi stato
        void conn_StateChange(object sender, StateChangeEventArgs e)
        {
            //textBox1.Text = 
            Debug.WriteLine("Stato cambiato da " + e.OriginalState + " a " + e.CurrentState);
        }



            private void button1_Click(object sender, EventArgs e)
        {



            // Attivo il mio delegato
            
            _conn.ConnectionString = _connString;

            //textBox1.Text = conn.State.ToString();
            
            this.Refresh();

            //Thread.Sleep(1000);

            _conn.Open();
            //textBox1.Text = conn.State.ToString();
            //this.Refresh();

            //if (_conn.State == ConnectionState.Open)
                //textBox1.Text = conn.State.ToString();

            //this.Refresh();

            //Thread.Sleep(1000);

            //_conn.Close();
            //textBox1.Text = conn.State.ToString();

            //this.Refresh();
              


        }


            // Il mio metodo
            private delegate void OpenDelegate();

            // 1. DICHIARO IL DELEGATO: Questa è la firma del mio delegato (voglio 1 oggetto come parametro)
            private delegate void MessageDelegate(object o);

            // 2. IMPLEMENTO IL METODO Questo è il metodo vero e proprio, che verrà puntato dal delegato
            // la firma deve essere la stessa del delegato
            static void MostraMessaggio(object o)
            {
                string str = (string) o;
                //MessageBox.Show(str);
            }


            private void button2_Click(object sender, EventArgs e)
            {
                // Gestore del cambio di stato
                
                _conn.ConnectionString = _connString;

                // Creo il mio delegato che punta al metodo OPEN
                OpenDelegate asyncOpen = new OpenDelegate(_conn.Open);

                // Chiamo il mio delegato in modo asyncrono e come callback gli faccio chiamare
                // il metodo OpenComplete
                IAsyncResult cookie = asyncOpen.BeginInvoke(OpenComplete, asyncOpen);

                // Qui posso continuare le mie attività

                // 3. CREO il mio delegato, facendolo puntare al mio metodo
                // Da ora in poi posso dimenticarmi del mio metodo e lavorare solo col delegato
                var delegatoPerMostrareIMessaggi = new MessageDelegate(MostraMessaggio);

                // 4. CHIAMO IN MODO ASINCRONO il mio delegato, 
                // passandogli come primo argomento il messaggio (che finirà dritto al mio metodo)
                // senza gestire callback
                IAsyncResult cookie2 = delegatoPerMostrareIMessaggi.BeginInvoke("chiuditi!", null, null);

                // Chiudo la sessione asincrona, qui dovrei trappare le eccezioni
                delegatoPerMostrareIMessaggi.EndInvoke(cookie2);

            }

            // Metodo di callback
            private void OpenComplete(IAsyncResult cookie)
            {
                // Prendo riferimento del delegato, castato dal mio cookie
                OpenDelegate openDelegate = (OpenDelegate)cookie.AsyncState;

                try
                {


                    // Qui termino l'operazione asincrona
                    openDelegate.EndInvoke(cookie);
                    //MessageBox.Show("Open completed!");
                }
                // Importante: qui catturo gli errori delle operazioni asincrone
                catch (Exception ex)
                {

                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    //_conn.Close();

                }

            }

            private void button3_Click(object sender, EventArgs e)
            {
                _conn.Close();
            }

            private void button4_Click(object sender, EventArgs e)
            {
                DataTable agMotivo = new DataTable();
                //agMotivo = _conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
                OleDbCommand selectQuery = new OleDbCommand("select * from AG_MOTIVO", _conn);

                agMotivo.Load(selectQuery.ExecuteReader(CommandBehavior.SingleResult));

                dataGridView1.DataSource = agMotivo;

                // Ritorna: Stored procedure 'sp_oledb_tables' not found.

                MessageBox.Show(agMotivo.Rows.Count.ToString());

            }

            private void button5_Click(object sender, EventArgs e)
            {
                _connOdbc.ConnectionString = _connStringOdbc;

                _connOdbc.Open();

               

            }

            private void button6_Click(object sender, EventArgs e)
            {
                _connOdbc.Close();
            }

            private void button7_Click(object sender, EventArgs e)
            {
                // Uso un datatable per leggere la tabella ag_motivo
                DataTable agMotivo = new DataTable();
                // Uso un comando per eseguire la select
                OdbcCommand select = new OdbcCommand();

                select.CommandType = CommandType.Text;
                select.CommandText = "select * from AG_MOTIVO";
                select.Connection = _connOdbc;


                // Metodo per caricare una datatable
                agMotivo.Load(select.ExecuteReader());

                // Sintassi non funzionante
                //agMotivo = _connOdbc.GetSchema(OdbcMetaDataCollectionNames.Tables);

                // Scrivo le righe
                textBox1.Text = "Totale righe: " + agMotivo.Rows.Count.ToString();

                // Attivo il binding tra datagrid e datatable
                dataGridView1.DataSource = agMotivo;

                // Scrivo anche su file
                var sw = new StreamWriter(@"c:\temp\tabella.txt", false, Encoding.UTF8);

                foreach (DataRow row in agMotivo.Rows)
                {
                    string idMotivo;
                    string dsMotivo;
                    string output;

                    idMotivo = row["ID_MOTIVO"].ToString().Trim();
                    dsMotivo = row["DS_MOTIVO"].ToString().Trim();

                    output = String.Format("ID_MOTIVO: {0} DS_MOTIVO {1}", idMotivo, dsMotivo);
   
                    sw.WriteLine(output);
                }

                sw.Close();




            }

            private void button8_Click(object sender, EventArgs e)
            {
                OdbcCommand query = new OdbcCommand("update AN_ENTI set FL_MEZZI_SOC = null where ID_ENTE = 100");
                OdbcTransaction trans = _connOdbc.BeginTransaction(IsolationLevel.ReadUncommitted);
                int ret;

                ret = 0;

                query.Connection = _connOdbc;
                query.Transaction = trans;
                try
                {
                    ret = query.ExecuteNonQuery();
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    _connOdbc.Close();
                }
                




            }

            private void button10_Click(object sender, EventArgs e)
            {
                string updateQuery;
                OleDbCommand cmd;
                OleDbTransaction trans;
                int rowsAffected;

                updateQuery = "update AN_ENTI set FL_MEZZI_SOC =  FL_MEZZI_SOC where ID_ENTE < 10";

                trans = _conn.BeginTransaction(IsolationLevel.ReadCommitted);

                cmd = new OleDbCommand(updateQuery, _conn, trans);
                cmd.CommandTimeout = 1000; // Timeout

                // Metodo per esuire SQL che non danno risultati
                rowsAffected = cmd.ExecuteNonQuery();

                trans.Commit();

                MessageBox.Show("Rows affected: " + rowsAffected.ToString());



            }

            private void button11_Click(object sender, EventArgs e)
            {
                string selectQuery = "select * from AG_MOTIVO ";
                
                OleDbCommand cmd = new OleDbCommand(selectQuery, _conn);
                OleDbDataReader dr;

                dr = cmd.ExecuteReader(CommandBehavior.SingleResult);

                if (!dr.HasRows)
                {
                    MessageBox.Show("Nessuna Riga!");
                    return;
                }

                while (dr.Read())
                {
                    Debug.WriteLine(String.Format("ID {0} - Descrizione {1} ", dr[0].ToString(), dr["DS_MOTIVO"].ToString()));
                }

                dr.Close();
                dr.Dispose();

                cmd.Dispose();


                
            }

            private void button12_Click(object sender, EventArgs e)
            {
                string selectOneColumn = "select DS_MOTIVO from AG_MOTIVO where ID_MOTIVO = 3";
                object obj;
                string ds_motivo;
                
                OleDbCommand cmd = new OleDbCommand(selectOneColumn, _conn);

                obj = cmd.ExecuteScalar();
                ds_motivo = (string) obj;

                MessageBox.Show(ds_motivo);

                cmd.Dispose();


            }

            private void button13_Click(object sender, EventArgs e)
            {
                string selectWithParm = "select * from AN_ENTI where AC_CENTRALE = ? AND  DS_LOCALITA= ? ";
                DataTable dt = new DataTable();

                OleDbCommand cmd = new OleDbCommand(selectWithParm, _conn);
                // In realtà la descrizione serve solo per chiarezza
                cmd.Parameters.AddWithValue("AC_CENTRALE", "BT1");
                cmd.Parameters.AddWithValue("DS_LOCALITA", "MILANO");


                dt.Load(cmd.ExecuteReader());

                dataGridView1.DataSource = dt;

            }

            private void button14_Click(object sender, EventArgs e)
            {

                string selectQuery = "select ID_ENTE, DS_ENTE, VL_CIVICO, AC_ENTE from AN_ENTI WHERE DS_LOCALITA = 'MILANO' AND AC_CENTRALE = 'BT1'";

                OleDbCommand cmd = new OleDbCommand(selectQuery, _conn);
                OleDbDataReader dr;
                Byte[] buffer = new byte[20];


                dr = cmd.ExecuteReader(CommandBehavior.SingleResult);

                if (!dr.HasRows)
                {
                    MessageBox.Show("Nessuna Riga!");
                    return;
                }

                // Questa soluzione va bene per leggere riga per riga, campo per campo
                while (dr.Read())
                {
                    
                    for (int campo = 0; campo < dr.FieldCount; campo++)
                    {

                        // Ottengo nome del campo
                        string str = dr.GetName(campo);

                        // mi proteggo dal NULL e quindi ottengo valore del campo
                        if (!dr.IsDBNull(campo))
                        {
                            string val = dr.GetValue(campo).ToString();
                            MessageBox.Show(String.Format("Campo {0} = {1}", str, val));
                        }

                    }

                }

                dr.Close();
                dr.Dispose();

                cmd.Dispose();




            }

            private void button15_Click(object sender, EventArgs e)
            {
                string multipleQueries =
                    "select DS_MOTIVO from AG_MOTIVO where ID_MOTIVO = 3; select ID_ENTE, DS_ENTE, VL_CIVICO, AC_ENTE from AN_ENTI WHERE DS_LOCALITA = 'MILANO' AND AC_CENTRALE = 'BT1'";

                OleDbCommand cmd = new OleDbCommand(multipleQueries, _conn);
                OleDbDataReader dr;

                dr = cmd.ExecuteReader();

                do
                {
                    MessageBox.Show("nuova query");
                    while (dr.Read())
                    {
                        string str = String.Format("Valore {0}", dr[0].ToString());
                        MessageBox.Show(str);
                    }
                    
                } while (dr.NextResult()); 

                dr.Close();
                dr.Dispose();

                cmd.Dispose();


            }

            private void button16_Click(object sender, EventArgs e)
            {
                // Creazione di un dataset tramite inserimento manuale (anziche da una query)
                // 1) creo il DataSet (sarà solitamente uno solo, dato che puo' contenere piu' tabelle e relazioni)
                // 2) creo il DataTable
                // 2b) imposto eventuali attributi
                // 3) creo almeno un DataColumn impostando proprieta come null, defaultvalue e unique
                // 4) aggiungo il DataColumn alla collezione di DataTable's Columns
                // 5) creo la PK assegnando un array di DataColumn alla proprieta PK del mio DataTable
                // 6) Creo una o piu' constraint tramite la classe UniqueConstraint o ForeignKeyConstrant e le aggiungo
                //    alla collezione di DataTable's Constraint
                // 7) Finalmente aggiungo la mia DataTable ben composta alla collezione di DataSet's Tables
                // 8) Se mi servono creo tutte le relazioni tra le mie tabelle del DataSet, tramite DataRelation e la collezione di Relations

                // 1)
                DataSet ds = new DataSet("myDataSet");

                // 2)
                DataTable dtEmp = new DataTable("Employees");

                // 2b) capacità iniziale
                dtEmp.MinimumCapacity = 200;

                // 3)
                DataColumn dcFirstName = new DataColumn("FirstName", typeof(string));
                DataColumn dcLastName = new DataColumn("LastName", typeof(string));
                DataColumn dcBirthDate = new DataColumn("BirthDate", typeof(DateTime));

                // Imposto la lunghezza max di una colonna e un valore di default
                DataColumn dcCity = new DataColumn("City", typeof(string));
                dcCity.MaxLength = 20;
                dcCity.DefaultValue = "Milano";

                // Creo una colonna come campo calcolato
                DataColumn dcFullName = new DataColumn("FullName", typeof(string), "FirstName + ' ' + LastName");
                
                // Creo una colonna identity, come chiave primaria della mia tabella
                DataColumn dcEmpId = new DataColumn("EmpId", typeof(int));
                dcEmpId.AutoIncrement = true;
                dcEmpId.AutoIncrementSeed = 1;
                dcEmpId.AutoIncrementStep = 1;
                dcEmpId.AllowDBNull = false;
                dcEmpId.Unique = true;

                // 4)
                dtEmp.Columns.Add(dcFirstName);
                dtEmp.Columns.Add(dcLastName);
                dtEmp.Columns.Add(dcBirthDate);
                dtEmp.Columns.Add(dcCity);
                dtEmp.Columns.Add(dcFullName);
                dtEmp.Columns.Add(dcEmpId);

                // 5)
                DataColumn[] dcPk = new DataColumn[1] {dcEmpId};
                dtEmp.PrimaryKey = dcPk;

                // 6) Notazione veloce per aggiungere un'altra colonna. FK ?
                dtEmp.Columns.Add("DeptId", typeof (int));

                // 7)
                ds.Tables.Add(dtEmp);

                // Aggiunta nuovo record
                // 1) uso il metodo NewRow del DataTable per creare un oggetto di tipo DataRow che avra' lo stesso schema name della tabella
                // 2) assegno i valori a tutti i campi del mio DataRow (o almeno a quei campi non nullabili, privi di valore di default)
                // 3) Passo l'oggetto DataRow in pasto al metodo Add della collezione di Rows

                // 1)
                DataRow dr = dtEmp.NewRow();

                // 2)
                dr["FirstName"] = "Mauro";
                dr["LastName"] = "Maureschi";
                dr["BirthDate"] = DateTime.Today;
                //dr["City"] = "Milano";
                dr["DeptId"] = 5;

                // 3)
                dtEmp.Rows.Add(dr);

                DataRow dr2 = dtEmp.NewRow();
                dr2["FirstName"] = "Luca";
                dr2["LastName"] = "Bollini";
                dr2["BirthDate"] = DateTime.Today;
                dr2["City"] = "Bologna";
                dr2["DeptId"] = 3;
                dtEmp.Rows.Add(dr2);

                // Aggiunta di piu' record (da provare)
                // 1) Creo una stringa contenente il mio db con i valori nel formato:
                //      "Mauro";"Mareschi";31/12/2008;"Casalmaiocco";2
                // 2) Mi creo una regular expression creando dei gruppi
                //      """(?<firstname>[^""]+)"";....
                // 3) Inizio il caricamento con la BeginLoadData
                // 4) Leggo le righe 1 alla volta con la foreach
                // 5) Per ogni righa mi creo un object con i valori dei gruppi della regex
                // 6) Uso il metodo LoadDataRow, passando l'oggetto
                // 7) Termino il caricamento con il metodo EndLoadData

                dataGridView1.DataSource = dtEmp;


                DataRow drFind = dtEmp.Rows[1];

                //dtEmp.ImportRow(dr2);
               
                // Per cancellare:
                // Delete marca per la cancellazione
                // Remove cancella una riga, in modo definitivo

                //ds.Tables["Employees"].Rows[0].Delete();

                //MessageBox.Show("Riga 0: " + dr.RowState);

                //dtEmp.Rows.Remove(dr);

                // Marco una riga come errata, compare il ! affianco alla colonna
                dtEmp.Rows[1].SetColumnError(3, "errore ahi ahi ahi");
      
                // Creo un sottoinsieme di recordo tramite la select, le metto in un dataview
                // e le visualizzo nel mio datagrid

                DataView dv = new DataView();
                dv.Table = dtEmp;
                dv.RowFilter = "Firstname = 'Mauro'";
                dv.AllowNew = false;
                dv.RowStateFilter = DataViewRowState.Added | DataViewRowState.ModifiedCurrent;

                dataGridView2.DataSource = dv;

                dtEmp.AcceptChanges();

                // Registro l'evento di riga mutata, chiamando il delegato DataRowChangeEventHandler
                dv.Table.RowChanged += new DataRowChangeEventHandler(Table_RowChanged);

            }


            // Implemento il metodo per il cambio riga
            static void Table_RowChanged(object sender, DataRowChangeEventArgs row)
            {

                MessageBox.Show("Riga modificata " + row.Row[0] + " - " + row.Action.ToString());

            }


    }
}
